﻿using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

/// <summary>
///     语法树范围内的符号表。单个语法树拥有单独的宏符号表和本地符号表，两个符号表
///     之间的符号名不冲突，因为这两种符号在不同的阶段使用。
/// </summary>
public sealed class AnalysisTreeSymbolTable(SyntaxTree tree) : SymbolTable
{
    private readonly Dictionary<string, LabelSymbol> _labels = new(StringComparer.OrdinalIgnoreCase);
    private readonly SourceSymbolTable _macroSymbols = new();
    private readonly ConditionalWeakTable<Expression, ISymbol> _references = [];
    private readonly Dictionary<string, ITypeSymbol> _undefinedSymbols = new(StringComparer.OrdinalIgnoreCase);

    private SymbolTable? _parent;

    protected override Dictionary<string, ISymbol> Symbols { get; } = new(StringComparer.OrdinalIgnoreCase);


    public override ISymbol? DomainSymbol => null;

    public override ReadOnlySymbolTable? Parent => _parent;


    /// <summary>
    ///     设置当前符号表的父级表
    /// </summary>
    /// <param name="parent">父级符号表</param>
    internal void SetParent(SymbolTable parent)
    {
        _parent = parent;
    }
    

    protected override bool DeclareSymbolCore(ISymbol symbol)
    {
        // 如果是宏定义，添加到宏定义表中。
        return symbol.IsMacro
            ? _macroSymbols.DeclareSymbol((MacroSymbol)symbol)
            : Symbols.TryAdd(symbol.Name, symbol);
    }


    /// <summary>
    ///     获取当前已有的所有宏定义符号。
    /// </summary>
    public ImmutableArray<ISymbol> GetMacroSymbols()
    {
        return [.. _macroSymbols];
    }


    /// <summary>
    ///     更新一个未定义的符号名绑定的类型.
    /// </summary>
    /// <param name="name">添加的符号名</param>
    /// <param name="typeSymbol">符号名绑定的类型符号</param>
    public void UpdateUndefined(string name, ITypeSymbol typeSymbol)
    {
        if (!_undefinedSymbols.TryAdd(name, typeSymbol))
        {
            _undefinedSymbols[name] = typeSymbol;
        }
    }


    /// <summary>
    ///     查找指定名称的未定义符号
    /// </summary>
    /// <param name="name">符号名，不区分大小写</param>
    public ITypeSymbol? LookupUndefined(string name)
    {
        return _undefinedSymbols.GetValueOrDefault(name);
    }


    /// <summary>
    ///     获取符号表中指定名称的宏符号，如果不存在，
    ///     返回 <see langword="null" />
    /// </summary>
    /// <param name="macroName">宏名，区分大小写</param>
    public MacroSymbol? LookupMacroSymbol(string macroName)
    {
        return _macroSymbols.LookupLocalSymbol(macroName, true) as MacroSymbol;
    }


    /// <summary>
    ///     查找所有在当前语法树文件位置已声明的宏符号。
    /// </summary>
    /// <param name="position">文本位置</param>
    public ImmutableArray<MacroSymbol> LookupMacroSymbols(int position)
    {
        return [.._macroSymbols.Where(m => m.IsDeclared(tree.Uri, position)).OfType<MacroSymbol>()];
    }


    /// <summary>
    ///     查找指定文本位置所在节点的符号定义。
    /// </summary>
    /// <param name="position">文本位置，0开始</param>
    /// <returns>返回查找到的符号，如果所在位置没有节点或者节点不带有符号，返回<see langword="null" /></returns>
    public ISymbol? LookupSymbol(int position)
    {
        ITextNode? node = tree.LookupSyntaxNode(position);

        if (node == null || !node.Is<Expression>(out Expression? expression))
        {
            return null;
        }

        return _references.TryGetValue(expression, out ISymbol? symbol) ? symbol : null;
    }


    /// <summary>
    ///     查找语法树范围的行标签定义。
    /// </summary>
    /// <param name="name">标签名</param>
    public LabelSymbol? LookupLabel(string name)
    {
        return _labels.GetValueOrDefault(name) ?? (_parent switch
        {
            DomainSymbolTable domainSymbolTable => domainSymbolTable.LookupLabel(name),
            AnalysisTreeSymbolTable analysisTreeSymbolTable => analysisTreeSymbolTable.LookupLabel(name),
            _ => null
        });
    }


    /// <summary>
    ///     添加一个行标签符号，如果同名符号已存在，返回<see langword="false" />
    /// </summary>
    /// <param name="label">添加的符号</param>
    public bool DeclareLabel(LabelSymbol label)
    {
        return _labels.TryAdd(label.Name, label);
    }
}